/**
在 TypeScript 中， `any` 、 `unknown`  和  `void`  是三种特殊的类型，它们在类型系统中具有特定的用途和含义。以下是对这几种类型的总结：
  1. any
  - 定义： `any`  类型表示任意类型，允许变量可以是任何类型的值。使用  `any`  类型时，TypeScript 不会对该变量进行类型检查。
  - 用途：
    - 当你不知道某个变量的具体类型时，可以使用  `any` 。
    - 在逐步迁移 JavaScript 代码到 TypeScript 时，可以使用  `any`  来暂时绕过类型检查。
  - 缺点：过度使用  `any`  会失去 TypeScript 的类型安全性，可能导致运行时错误。
   示例：
  let value: any;
  value = 42;          // number
  value = "Hello";    // string
  value = true;       // boolean
  2. unknown

  - 定义： `unknown`  类型表示未知类型，类似于  `any` ，但更安全。使用  `unknown`  类型的变量在使用前必须进行类型检查。
  - 用途：
    - 当你需要一个变量可以是任意类型，但又希望在使用前进行类型验证时，可以使用  `unknown` 。
  - 优点：相比于  `any` ， `unknown`  强制要求开发者在使用值之前进行类型检查，从而提高了类型安全性。

   示例：
  let value: unknown;

  value = 42;          // number
  value = "Hello";    // string

  // 使用前需要进行类型检查
  if (typeof value === "string") {
    console.log(value.toUpperCase()); // 安全使用
  }
  3. void
  - 定义： `void`  类型表示没有任何类型，通常用于表示函数没有返回值。
  - 用途：
    - 当一个函数不返回任何值时，可以使用  `void`  类型。
    - 适用于那些只执行操作而不返回结果的函数。
    
   示例：
  function logMessage(message: string): void {
    console.log(message);
  }

  const result = logMessage("Hello, World!"); // result 的类型是 void
  4. 总结
  - any：允许任意类型，失去类型安全性，适用于不需要类型检查的场景。
  - unknown：表示未知类型，要求在使用前进行类型检查，提供更高的类型安全性。
  - void：表示没有返回值，通常用于没有返回结果的函数。
  在使用这些类型时，应根据具体的需求选择合适的类型，尽量避免过度使用  `any` ，以保持类型系统的优势。
 */
  // 1. any: 允许任意类型，失去类型安全性，适用于不需要类型检查的场景。
  let id: any = 42;
  id = true;
  id = "Hello";
  console.log(id.length);
  id = { name: "John any" }
  
  const infos: any[] = ["John", 12, true, {}, []];

  // 2. unknown: 表示未知类型，要求在使用前进行类型检查，提供更高的类型安全性。
  let foo: unknown = 42;
  foo = "Hello";
  // 要求必须进行类型的校验(缩小), 才能根据缩小之后的类型, 进行对应的操作
  if (typeof foo === "string") {
    console.log(foo.length, foo.split(" "));
  }

  // 3. void: 表示没有任何类型，通常用于表示函数没有返回值。
  // 在TS中如果一个函数没有任何的返回值, 那么返回值的类型就是void类型
  // 如果返回值是void类型, 那么我们也可以返回undefined(TS编译器允许这样做而已)
  function foo1(): void {
    console.log("foo1");
    // return undefined;
  }

  // 应用场景: 用来指定函数类型的返回值是void
  type LyricInfoType = { time: number, text: string }
  // parseLyric函数的数据类型: (lyric: string) => LyricInfoType[]
  function parseLyric(lyric: string): LyricInfoType[] {
    const lyricInfos: LyricInfoType[] = []
    // 解析
    return lyricInfos
  }

  // parseLyric => 函数/对象
  type FooType = () => void
  const foo2: FooType = () => {}

  type ExecFnType = (...args: any[]) => void
  const exec = (fn: ExecFnType) => {
    setTimeout(() => {
      fn("Hello", 19)
    }, 1000)
  }

  exec((name, age) => {
    console.log("callback", name, age)
  })

  // 4. never: 表示永远不会发生值的类型，通常用于表示函数抛出异常或无限循环的情况。
  // 应用场景: 1. 函数抛出异常 2. 函数永远不会有返回值(死循环)
  // function foo3(): never {
  //   while (true) {
  //     console.log("foo3");
  //   }
  //   throw new Error("error message")
  // }

  // 封装框架/工具库的时候可以使用一下never
  // 其他时候在扩展工具的时候, 对于一些没有处理的case, 可以直接报错
  function handleMessage(message: string | number | boolean) {
    switch (typeof message) {
      case "string":
        break;
      case "number":
        break;
      case "boolean":
        break;
      default:
        // never: 表示永远不会发生值的类型
        // 用于表示一些不存在的状态
        const check: never = message
    }
  }
  handleMessage(1234)

  // 5. tuple: 元组, 固定长度的数组
  // 使用数组类型; 不合适: 数组中最好存放相同的数据类型, 获取值之后不能明确的知道对应的数据类型
  const info1: any[] = ["tuple-name", 18, 1.88]
  const value = info1[0]

  // 使用对象类型(最多)
  const info2 = {
    name: "tuple-name-type",
    age: 18,
    height: 1.88
  }

  // 元组数据结构中可以存放不同的数据类型, 取出来的item也是有明确的类型
  const tupleInfo: [string, number, number] = ["tuple-name", 18, 1.88]
  const tuple = tupleInfo[0]

  // 在函数中使用元组类型是最多的(函数的返回值)
  function useState(initialState: number): [number, (newValue: number) => void]  {
    let stateValue = initialState
    function setValue(newValue: number) {
      stateValue = newValue
    }

    return [stateValue, setValue]
  }
  const [count, setCount] = useState(10)
  console.log(count);
  setCount(100)

  export {}
